using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using iPhOwa.Exchange.Attributes;
using iPhOwa.Exchange.ContentClasses.Fields;

namespace iPhOwa.Exchange.ContentClasses
{
	/// <summary>
	/// The base entity for exchange objects.
	/// </summary>
	[ExchangeContentClass(ContentClassNames.Item)]
	public abstract class Item
	{
		private static readonly IDictionary<Type, IList<PropertyInfo>> typePropertyCache = new Dictionary<Type, IList<PropertyInfo>>();

		/// <summary>
		/// A folder's total number of items, including subfolders.
		/// </summary>
		[ExchangeField(ItemFields.ChildCount)]
		public long ChildCount
		{
			get;
			set;
		}

		/// <summary>
		/// The item's content class.
		/// </summary>
		[ExchangeField(ItemFields.ContentClass)]
		public string ContentClass
		{
			get;
			set;
		}

		/// <summary>
		/// The date and time that the item was created.
		/// </summary>
		[ExchangeField(ItemFields.CreationDate)]
		public DateTime CreationDate
		{
			get;
			set;
		}

		/// <summary>
		/// The item's friendly display name.
		/// </summary>
		[ExchangeField(ItemFields.DisplayName)]
		public string DisplayName
		{
			get;
			set;
		}

		/// <summary>
		/// Indicates whether the folder item has subfolders.
		/// </summary>
		[ExchangeField(ItemFields.HasSubs)]
		public bool HasSubs
		{
			get;
			set;
		}

		/// <summary>
		/// The absolute URL of an item.
		/// </summary>
		[ExchangeField(ItemFields.Href)]
		public Uri Href
		{
			get;
			set;
		}

		/// <summary>
		/// Specifies the absolute URL of the folder that contains an item.
		/// </summary>
		[ExchangeField(ItemFields.ParentName)]
		public Uri ParentName
		{
			get;
			set;
		}

		/// <summary>
		/// Indicates whether an item has been read.
		/// </summary>
		[ExchangeField(ItemFields.Read)]
		public bool Read
		{
			get;
			set;
		}

		/// <summary>
		/// Specifies a unique identifier for an item.
		/// </summary>
		[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Uid")]
		[ExchangeField(ItemFields.Uid)]
		public string Uid
		{
			get;
			set;
		}

		/// <summary>
		/// Populate this object from the passed properties.
		/// </summary>
		public void Load(PropertyDictionary propertyHash)
		{
			Type t = GetType();

			if(!typePropertyCache.ContainsKey(t))
			{
				typePropertyCache.Add(t, t.GetProperties());
			}

			IList<PropertyInfo> properties = typePropertyCache[t];

			foreach(PropertyInfo info in properties)
			{
				IList<ExchangeFieldAttribute> attributes = new List<object>(info.GetCustomAttributes(typeof(ExchangeFieldAttribute), true))
						.ConvertAll<ExchangeFieldAttribute>(delegate(object o) { return o as ExchangeFieldAttribute; });

				foreach(ExchangeFieldAttribute attribute in attributes)
				{
					if(info.PropertyType == typeof(DateTime))
					{
						info.SetValue(this, propertyHash.GetDateTime(attribute.FullName), null);
					}
					else if(info.PropertyType == typeof(Boolean))
					{
						info.SetValue(this, propertyHash.GetBoolean(attribute.FullName), null);
					}
					else if(info.PropertyType == typeof(Int64))
					{
						info.SetValue(this, propertyHash.GetInt64(attribute.FullName), null);
					}
					else if(info.PropertyType == typeof(Int32))
					{
						info.SetValue(this, propertyHash.GetInt32(attribute.FullName), null);
					}
					else if(info.PropertyType == typeof(Uri))
					{
						info.SetValue(this, propertyHash.GetUri(attribute.FullName), null);
					}
					else if(info.PropertyType == typeof(String))
					{
						info.SetValue(this, propertyHash[attribute.FullName], null);
					}
				}
			}
		}
	}
}